package annotation

import (
	"go/ast"
	"regexp"
)

// SingleFileEntryVisitor 这部分和课堂演示差不多，但是我建议你们自己试着写一些
type SingleFileEntryVisitor struct {
	file *fileVisitor
}

func (s *SingleFileEntryVisitor) Get() File {
	return s.file.Get()
	//panic("implement me")
}

func (s *SingleFileEntryVisitor) Visit(node ast.Node) ast.Visitor {

	fl, ok := node.(*ast.File)

	if ok {
		s.file = &fileVisitor{
			ans: newAnnotations(fl, fl.Doc),
		}
		return s.file
	}

	return s

	//panic("implement me")
}

type fileVisitor struct {
	ans     Annotations[*ast.File]
	types   []*typeVisitor
	visited bool
}

func (f *fileVisitor) Get() File {
	typs := make([]Type, 0, 8)
	for _, visitor := range f.types {
		typs = append(typs, visitor.Get())
	}
	return File{
		Annotations: f.ans,
		Types:       typs,
	}
	//panic("implement me")
}

var annotationReg = regexp.MustCompile("//\\s+@(\\S+)(?:\\s+(.*?))?\\s*$")

func (f *fileVisitor) Visit(node ast.Node) ast.Visitor {

	ts, ok := node.(*ast.TypeSpec)

	if !ok {
		return f
	}

	//ans := make([]Annotation, 0, 8)
	//
	//for _, comment := range ts.Doc.List {
	//	sub := annotationReg.FindStringSubmatch(comment.Text)
	//	if len(sub) == 3 {
	//		ans = append(ans, Annotation{
	//			Key:   sub[1],
	//			Value: sub[2],
	//		})
	//	}
	//}

	tv := &typeVisitor{
		ans: newAnnotations(ts, ts.Doc),
	}

	f.types = append(f.types, tv)
	return tv
	//panic("implement me")
}

type File struct {
	Annotations[*ast.File]
	Types []Type
}

type typeVisitor struct {
	ans    Annotations[*ast.TypeSpec]
	fields []Field
}

func (t *typeVisitor) Get() Type {
	return Type{
		Annotations: t.ans,
		Fields:      t.fields,
	}
	//panic("implement me")
}

func (t *typeVisitor) Visit(node ast.Node) (w ast.Visitor) {

	f, ok := node.(*ast.Field)

	if !ok {
		return t
	}

	field := Field{
		Annotations: newAnnotations(f, f.Doc),
	}

	t.fields = append(t.fields, field)

	//panic("implement me")
	return nil
}

type Type struct {
	Annotations[*ast.TypeSpec]
	Fields []Field
}

type Field struct {
	Annotations[*ast.Field]
}
